﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using com.yoozoo.gta.Extension;
using UnityEngine;


public class ReddotNode
{

    public enum ReddotNodeType
    {
        NONE = 1,
    }
    /// <summary>
    /// 红点管理器对象
    /// 注意 必须传递子对象 因为红点管理器维护一份全局的 路径-节点 表
    /// 注意 删除节点时 需要同时从全局表中移除 在Dispose方法中已实现
    /// </summary>
    public ReddotManager m_manager;
    /// <summary>
    /// 子节点列表
    /// </summary>
    public List<ReddotNode> m_childList = new List<ReddotNode>();
    /// <summary>
    /// 子节点相对路径散列表
    /// </summary>
    public Dictionary<string, ReddotNode> m_childDict = new Dictionary<string, ReddotNode>();
    /// <summary>
    /// 关心该节点值的显示对象列表
    /// 当节点更新时 所有关心该节点的显示对象 都会更新到最新值
    /// </summary>
    public List<ReddotNodeItem> m_nodeItemList = new List<ReddotNodeItem>();
    /// <summary>
    /// 父节点
    /// </summary>
    public ReddotNode m_parent;
    /// <summary>
    /// 节点全路径 例如 task.taskMain
    /// </summary>
    public string m_path;
    /// <summary>
    /// 节点相对父节点的路径 taskMain
    /// </summary>
    public string m_relativePath;
    /// <summary>
    /// 暂未使用
    /// </summary>
    public int m_type;
    /// <summary>
    /// 当前节点上的节点值
    /// </summary>
    public int m_value;
    /// <summary>
    /// 暂未使用
    /// </summary>
    public bool m_dirty;
    /// <summary>
    /// 调用lua方法 计算当前红点数值
    /// 叶子节点时会设置该值
    /// </summary>
    public Func<int> m_func;
    public int Value
    {
        get => m_value;
        set => m_value = value;
    }
    public bool IsDirty
    {
        get => m_dirty;
        set => m_dirty = value;
    }
    /// <summary>
    /// 是否是根节点
    /// </summary>
    public bool IsRoot
    {
        get => m_parent == null;
    }

    public ReddotNode(string path, string relativePath)
    {
        m_path = path;
        m_relativePath = relativePath;
    }
    /// <summary>
    /// 从下往上冒泡计算并更新节点值
    /// </summary>
    public void Bubble()
    {
        CalcValue();
        UpdateNode();
        
        m_parent?.Bubble();
    }
    
    /// <summary>
    /// 计算当前节点的值
    /// 注意 当该节点是叶子节点时  会调用lua方法计算当前节点值
    /// 注意 如果该节点不是叶子节点时 只会计算其子节点的节点值之和不会递归计算
    /// </summary>
    /// <returns></returns>
    public bool CalcValue()
    {
        int oldValue = Value;
        
        Value = 0;
        if (m_childList.Count > 0)
        {
            foreach (var node in m_childList)
            {
                Value += node.Value;
            }
        }
        else
        {
            if (m_func != null)
                Value = m_func.Invoke();
        }

        if (oldValue != Value)
        {
            IsDirty = true;
        }

        return IsDirty;
    }

    /// <summary>
    /// 更新当前节点的值
    /// 更新所有关心该节点的显示对象上的红点值
    /// </summary>
    public void UpdateNode()
    {
        foreach (var nodeItem in m_nodeItemList)
        {
            if (nodeItem.Valid())
            {
                nodeItem.SetValue(Value);
            }
            else
            {
                
#if UNITY_EDITOR
                UnityEngine.Debug.LogError($"[红点系统]无效的RddotNodeItem显示项:{m_path}");
#else
                UnityEngine.Debug.Log($"[红点系统]无效的RddotNodeItem显示项:{m_path}");
#endif
            }
        }
    }

    public ReddotNode AddNode(string relativePath)
    {
        ReddotNode node = null;
        if (!m_childDict.TryGetValue(relativePath, out node))
        {
            node = new ReddotNode($"{this.m_path}.{relativePath}", relativePath);
            node.m_parent = this;

            m_childDict.Add(relativePath, node);
            m_childList.Add(node);
        }

        return node;
    }

    public void RemoveNode(ReddotNode node)
    {
        node.Dispose();
        m_childList.Remove(node);
        m_childDict.Remove(node.m_relativePath);

        if (m_childList.Count == 0)
        {
            this.RemoveFromParent();
        }
        
    }

    /// <summary>
    /// 叶子节点 添加lua方法调用 用于计算当前节点的值
    /// 注意 只有叶子节点才会设置该方法
    /// </summary>
    /// <param name="func"></param>
    public void AddListener(Func<int> func)
    {
        m_func = func;
    }

    /// <summary>
    /// 将红点显示对象添加到该节点上
    /// </summary>
    /// <param name="nodeItem"></param>
    public void AddNodeItem(ReddotNodeItem nodeItem)
    {
        if (!m_nodeItemList.Contains(nodeItem))
        {
            m_nodeItemList.Add(nodeItem);
            UpdateNode();
        }
        else
        {
#if UNITY_EDITOR
            UnityEngine.Debug.LogError($"[红点系统]重复的NodeItem:{nodeItem.m_path}", nodeItem.gameObject);
#else
            UnityEngine.Debug.Log($"[红点系统]重复的NodeItem:{nodeItem.m_path}");
#endif
        }
    }
    /// <summary>
    /// 将红点显示对象从该节点上移除
    /// </summary>
    /// <param name="nodeItem"></param>
    public void RemoveNodeItem(ReddotNodeItem nodeItem)
    {
        if (m_nodeItemList.Contains(nodeItem))
        {
            m_nodeItemList.Remove(nodeItem);
        }
    }
    /// <summary>
    /// 节点更新事件派送
    /// 注意 如果派送的是叶子节点 则冒泡调用
    /// 注意 如果派送的不是叶子节点的值 则递归到其所有的叶子节点 更新全部叶子节点
    /// TODO:性能问题？
    /// </summary>
    public void Dispatch()
    {
        //叶子节点
        if (m_childList.Count == 0)
        {
            Bubble();
        }
        else
        {
            foreach (var node in m_childList)
            {
                node.Dispatch();
            }
        }
    }

    /// <summary>
    /// 将该节点从父节点移除
    /// 注意 移除时请使用 ReddotManager中的RemoveNode 方法来移除节点
    /// </summary>
    public void RemoveFromParent()
    {
        this.m_parent?.RemoveNode(this);
    }
	
    /// <summary>
    /// 清除当前节点相关消息
    /// </summary>
    public void Dispose()
    {
        //从全局缓存中删除
        m_manager.ClearNodeDict(this);
        
        foreach (var nodeItem in m_nodeItemList)
        {
            nodeItem.SetValue(0);
        }
        
        m_func = null;
    }
}
